﻿using Pay.Core;
using Pay.Data;
using Pay.DTO;
using Pay.IService;
using Pay.Service.Cache;
using Pay.TO;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Pay.Service {
    public class ConsumeItemService : ServiceBase, IConsumeItemService, IDisposable {
        private IUnitOfWork _iUnitOfWork;
        private IMerchantBankCardService _iMerchantBankCardService;
        private ISettingService _iSettingService;
        public ConsumeItemService(IUnitOfWork iUnitOfWork, IMerchantBankCardService iMerchantBankCardService, ISettingService iSettingService) : base(iUnitOfWork) {
            _iUnitOfWork = iUnitOfWork;
            _iMerchantBankCardService = iMerchantBankCardService;
            _iSettingService = iSettingService;
        }

        #region 后台管理
        #region 消费项目
        /// <summary>
        /// 获得消费项目列表
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public PagedResult<consume_item_dto> GetConsumeItems(ConsumeItemQuery query) {
            var filter = PredicateBuilder.True<ConsumeItem>();
            if (!string.IsNullOrEmpty(query.title)) {
                filter = filter.And(c => c.Title == query.title);
            }
            if (!string.IsNullOrEmpty(query.disabled)) {
                bool value = query.disabled == "1" ? true : false;
                filter = filter.And(o => o.Disabled == value);
            }
            if (!string.IsNullOrEmpty(query.begin_time)) {
                DateTime time = DateTime.Parse(query.begin_time);
                filter = filter.And(c => c.CreateTime >= time);
            }
            if (!string.IsNullOrEmpty(query.end_time)) {
                DateTime time = DateTime.Parse(query.end_time).AddDays(1);
                filter = filter.And(c => c.CreateTime <= time);
            }
            var result = context.ConsumeItem.FromCachePaged<ConsumeItem, consume_item_dto>(query.page, query.size, filter, orderBy => orderBy.OrderBy(o => o.Sort).ThenByDescending(o => o.CreateTime));
            return result;
        }

        /// <summary>
        /// 获得消费项目
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public consume_item_dto GetConsumeItem(long id) {
            return context.ConsumeItem.Find(id).ToDtoObject<consume_item_dto>();
        }


        /// <summary>
        /// 新增消费项目
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public ResultMessage<int> AddConsumeItem(consume_item_dto dto) {
            if (context.ConsumeItem.Exist(o => o.ConsumeType == dto.consume_type && dto.consume_type != EConsumeItemType.Other))
                return new ResultMessage<int>(501, "所选消费项目类型已存在，不能重复添加");
            dto.create_time = DateTime.Now;
            ConsumeItem model = new ConsumeItem();
            dto.ToDtoObject(model);
            context.ConsumeItem.Add(model);
            int result = _iUnitOfWork.Commit("ConsumeItem");
            return ResultToJson.Json(result > 0 ? " 保存成功" : "保存失败", result);
        }

        /// <summary>
        /// 更新消费项目
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public ResultMessage<int> UpdateConsumeItem(consume_item_dto dto) {
            ConsumeItem model = context.ConsumeItem.FindById(dto.id);
            if (model.ConsumeType != dto.consume_type && context.ConsumeItem.Exist(o => o.ConsumeType == dto.consume_type && dto.consume_type != EConsumeItemType.Other))
                return new ResultMessage<int>(501, "所选消费项目类型已存在，不能重复添加");
            dto.ToDtoObject(model);
            int result = _iUnitOfWork.Commit("ConsumeItem");
            return ResultToJson.Json(result > 0 ? " 保存成功" : "未做任何修改", result);
        }

        /// <summary>
        /// 修改消费项目状态
        /// </summary>
        /// <param name="id"></param>
        /// <param name="status"></param>
        /// <returns></returns>
        public int UpdateDisabled(long id, int isDisabled) {
            ConsumeItem model = context.ConsumeItem.FindById(id);
            model.Disabled = isDisabled == 1 ? true : false;
            int result = _iUnitOfWork.Commit("ConsumeItem");
            return result;
        }
        #endregion

        #region 消费-商品兑换
        /// <summary>
        /// 获得消费商品列表
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public PagedResult<consume_product_dto> GetConsumeProducts(ConsumeProductQuery query) {
            var filter = PredicateBuilder.True<ConsumeProduct>();
            if (!string.IsNullOrEmpty(query.title)) {
                filter = filter.And(c => c.Title == query.title);
            }
            if (!string.IsNullOrEmpty(query.status)) {
                int value = int.Parse(query.status);
                filter = filter.And(c => c.Status == (EConsumeProductStatus)value);
            }
            if (!string.IsNullOrEmpty(query.begin_time)) {
                DateTime time = DateTime.Parse(query.begin_time);
                filter = filter.And(c => c.CreateTime >= time);
            }
            if (!string.IsNullOrEmpty(query.end_time)) {
                DateTime time = DateTime.Parse(query.end_time).AddDays(1);
                filter = filter.And(c => c.CreateTime <= time);
            }
            var result = context.ConsumeProduct.FromCachePaged<ConsumeProduct, consume_product_dto>(query.page, query.size, filter, orderBy => orderBy.OrderByDescending(o => o.Sort));
            if (result.rows != null && result.rows.Count() > 0) {
                foreach (var row in result.rows) {
                    row.to_shipping_num = context.UserComsumeHis.Where(o => o.ProductId == row.id && o.Status == EUserComsumeHisStatus.ToShipping).Count();
                }
            }
            return result;
        }

        /// <summary>
        /// 获得消费商品
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public consume_product_dto GetConsumeProduct(long id) {
            return context.ConsumeProduct.Find(id).ToDtoObject<consume_product_dto>();
        }

        /// <summary>
        /// 新增消费商品
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public int AddConsumeProduct(consume_product_dto dto) {
            //if (dto.product_num_limit != null && dto.status == EConsumeProductStatus.Putaway && dto.product_num_limit <= 0)
            //    throw new ServerErrorException("商品剩余可兑换数量必须大于0");
            //if (dto.product_num_limit != null && dto.product_num_limit < 0)
            //    throw new ServerErrorException("商品剩余可兑换数量不能小于0");
            dto.create_time = DateTime.Now;
            dto.update_time = DateTime.Now;
            ConsumeProduct model = new ConsumeProduct();
            dto.ToDtoObject(model);
            context.ConsumeProduct.Add(model);
            int result = _iUnitOfWork.Commit("ConsumeProduct");
            return result;
        }

        /// <summary>
        /// 更新消费商品
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public int UpdateConsumeProduct(consume_product_dto dto) {
            //if (dto.product_num_limit != null && dto.status == EConsumeProductStatus.Putaway && dto.product_num_limit <= 0)
            //    throw new ServerErrorException("商品剩余可兑换数量必须大于0");
            //if (dto.product_num_limit != null && dto.product_num_limit < 0)
            //    throw new ServerErrorException("商品剩余可兑换数量不能小于0");
            ConsumeProduct model = context.ConsumeProduct.FindById(dto.id);
            dto.ToDtoObject(model);
            model.UpdateTime = DateTime.Now;
            //if (model.ProductNumLimit.HasValue && model.ProductNumLimit == 0) {
            //    model.Status = EConsumeProductStatus.SoldEnd;
            //}
            int result = _iUnitOfWork.Commit("ConsumeProduct");
            return result;
        }

        /// <summary>
        /// 修改消费商品状态
        /// </summary>
        /// <param name="id"></param>
        /// <param name="status"></param>
        /// <returns></returns>
        public int UpdateConsumeProductStatus(long id, int status) {
            ConsumeProduct model = context.ConsumeProduct.FindById(id);
            model.Status = (EConsumeProductStatus)(status);
            int result = _iUnitOfWork.Commit("ConsumeProduct");
            return result;
        }

        #endregion

        #region 用户消费记录
        /// <summary>
        /// 用户消费记录
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public PagedResult<user_comsume_his_dto_ex> GetUserComsumeHiss(UserComsumeHisQuery query) {
            var filter = PredicateBuilder.True<UserComsumeHis>();
            if (!string.IsNullOrEmpty(query.consume_type_value)) {
                int value = int.Parse(query.consume_type_value);
                filter = filter.And(c => c.ConsumeType == (EConsumeItemType)value);
            }
            if (!string.IsNullOrEmpty(query.info)) {
                filter = filter.And(c => c.Info == query.info);
            }
            if (!string.IsNullOrEmpty(query.product_id)) {
                long productId = long.Parse(query.product_id);
                filter = filter.And(c => c.ProductId == productId);
            }
            if (!string.IsNullOrEmpty(query.status)) {
                int value = int.Parse(query.status);
                filter = filter.And(c => c.Status == (EUserComsumeHisStatus)value);
            }
            if (!string.IsNullOrEmpty(query.name)) {
                filter = filter.And(o => o.Merchant.Name == query.name);
            }
            if (!string.IsNullOrEmpty(query.mobile)) {
                filter = filter.And(o => o.Merchant.Mobile == query.mobile);
            }
            if (!string.IsNullOrEmpty(query.begin_time)) {
                DateTime value = DateTime.Parse(query.begin_time);
                filter = filter.And(c => c.CreateTime >= value);
            }
            if (!string.IsNullOrEmpty(query.end_time)) {
                DateTime value = DateTime.Parse(query.end_time).AddDays(1);
                filter = filter.And(c => c.CreateTime <= value);
            }
            var page = context.UserComsumeHis.FromCachePaged<UserComsumeHis, user_comsume_his_dto>(query.page, query.size, filter, orderBy => orderBy.OrderByDescending(o => o.CreateTime));

            List<user_comsume_his_dto_ex> rows = new List<user_comsume_his_dto_ex>();
            foreach (var h in page.rows) {
                user_comsume_his_dto_ex model = new user_comsume_his_dto_ex();
                h.ToCopyProperty(model);
                if (model.ship_adress_id != null) {
                    ShippingAddress shippingAddress = context.ShippingAddresses.Where(o => o.Id == (long)model.ship_adress_id).FirstOrDefault();
                    if (shippingAddress != null) {
                        model.ship_to = shippingAddress.ShipTo;
                        model.ship_phone = shippingAddress.Phone;
                        Region region = context.Regions.FindById(shippingAddress.RegionId);
                        if (region != null) {
                            model.user_address = region.RegionName + shippingAddress.Address;
                        }
                    }
                }
                rows.Add(model);
            }
            var result = new PagedResult<user_comsume_his_dto_ex>(rows, page.total_result, query.page, query.size);
            return result;
        }

        /// <summary>
        /// 修改用户消费记录状态
        /// </summary>
        /// <param name="id"></param>
        /// <param name="status"></param>
        /// <returns></returns>
        public int UpdateUserComsumeHisStatus(long id, int status) {
            UserComsumeHis model = context.UserComsumeHis.FindById(id);
            model.Status = (EUserComsumeHisStatus)(status);
            int result = _iUnitOfWork.Commit();
            return result;
        }
        #endregion
        #endregion

        #region APP
        /// <summary>
        /// App获得项目消费列表
        /// </summary>
        /// <returns></returns>
        public List<app_consume_item_dto> AppGetConsumeItemList() {
            return context.ConsumeItem.Where(o => o.Disabled == false).OrderBy(o => o.Sort).FromCache<ConsumeItem, app_consume_item_dto>("ConsumeItem");
        }
        public List<app_consume_item_dto> AppGetConsumeItemList(ConsumeQuery query) {
            var filter = PredicateBuilder.True<ConsumeItem>();
            filter = filter.And(o => o.Disabled == false);
            if (query.is_type) filter = filter.And(s => s.IsAppStoreShow == true);

            return context.ConsumeItem.Where(filter).OrderBy(o => o.Sort).FromCache<ConsumeItem, app_consume_item_dto>("ConsumeItem");
        }

        /// <summary>
        /// App获得商品兑换 商品分页列表
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public PagedResult<app_consume_product_dto> AppConsumeProductPageList(PageQuery query) {
            var filter = PredicateBuilder.True<ConsumeProduct>();
            filter = filter.And(o => o.Status == EConsumeProductStatus.Putaway);
            var result = context.ConsumeProduct.FromCachePaged<ConsumeProduct, app_consume_product_dto>(query.page, query.size, filter, orderBy => orderBy.OrderByDescending(c => c.Sort));
            //消费项目点击数+1
            //ConsumeItem consumeItem = context.ConsumeItem.Where(o => o.ConsumeType == EConsumeItemType.ExchangeProduct).FirstOrDefault();
            //consumeItem.ClickNum = consumeItem.ClickNum + 1;
            //_iUnitOfWork.Commit("ConsumeItem");
            var setting = _iSettingService.GetTokenSetting().token;
            if(result.rows != null && result.rows.Count() > 0) {
                foreach(var row in result.rows) {
                    row.red_drill = row.sale_price * setting.exchange_rate;
                    row.detail = HtmlContentHelper.ReplaceHtmlTag(row.detail, 28);
                }
            }
            return result;
        }

        /// <summary>
        /// App根据商品Id 获得商品
        /// </summary>
        /// <param name="productId"></param>
        /// <returns></returns>
        public app_consume_product_dto AppGetComsumeProduct(long productId) {
            var model = context.ConsumeProduct.Where(c => c.Id == productId).FromCacheFirstOrDefault<ConsumeProduct, app_consume_product_dto>();
            var setting = _iSettingService.GetTokenSetting().token;
            model.red_drill = model.sale_price * setting.exchange_rate;
            return model;
        }

        private static readonly object objkey = new object();

        /// <summary>
        /// App 商品兑换
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="productId"></param>
        /// <param name="red_drill">前端显示所需红钻,若后台变更,和前端显示不一致,提醒用户刷新</param>
        /// <returns></returns>
        public bool AppExchangeProduct(long userId, long productId, decimal red_drill, long? shipAddressId) {
            lock (objkey) {
                //判断 是否绑定银行卡 未绑定银行卡不允许兑换
                //var bankCard = _iMerchantBankCardService.GetBankCardByMerchantId(userId);
                //if (bankCard == null)
                //    throw new ServerErrorException("您未绑定银行卡，不能进行兑换，请使用最新版本APP，到“我的->账号设置->银行卡管理”中进行绑定");
                //else if (bankCard.status == EMerchantBankCardStatus.ToAudit)
                //    throw new ServerErrorException("您的银行卡信息正在审核中，不能进行兑换，请耐心等待");
                //else if (bankCard.status == EMerchantBankCardStatus.AuditFail)
                //    throw new ServerErrorException("您的银行卡信息审核未通过，不能进行兑换，请到“我的->账号设置->银行卡管理”中重新提交");
                using (var trans = context.Database.BeginTransaction()) {
                    try {
                        ConsumeItem consumeItem = context.ConsumeItem.Where(o => o.ConsumeType == EConsumeItemType.ExchangeProduct).FirstOrDefault();
                        ConsumeProduct consumeProduct = context.ConsumeProduct.FindById(productId);
                        if (consumeProduct.Status != EConsumeProductStatus.Putaway)
                            throw new ServerErrorException("该商品已下架");
                        if (consumeProduct.ProductNumLimit != null && consumeProduct.ProductNumLimit <= 0)
                            throw new ServerErrorException("该商品已售馨");
                        if (consumeProduct.BeginTime != null && consumeProduct.BeginTime >= DateTime.Now)
                            throw new ServerErrorException("该商品即将开放");
                        var setting = _iSettingService.GetTokenSetting().token;
                        var consume_red = consumeProduct.SalePrice * setting.exchange_rate;
                        if (consume_red != red_drill)
                            throw new ServerErrorException("商品所需红钻数量已发生变更,请刷新重试");

                        //用户消费红钻记录
                        UserComsumeHis userComsumeHis = new UserComsumeHis() {
                            UserId = userId,
                            ConsumeType = EConsumeItemType.ExchangeProduct,
                            Info = consumeProduct.Title,
                            ProductId = consumeProduct.Id,
                            ConsumeRedDrill = consume_red,
                            CreateTime = DateTime.Now,
                            ShipAdressId = shipAddressId
                        };

                        RedRecord redRecord = context.RedRecord.Where(o => o.MerchantId == userId).FirstOrDefault();
                        if ((redRecord.TotalRedDrill - redRecord.ConsumeRedDrill) < consume_red) {
                            throw new ServerErrorException("您的红钻不足，无法进行兑换，等攒够红钻再来吧！");
                        }

                        //允许兑换
                        //用户消费红钻增加
                        redRecord.ConsumeRedDrill += consume_red;
                        //记录成功的消费记录
                        userComsumeHis.Status = EUserComsumeHisStatus.ToShipping;
                        context.UserComsumeHis.Add(userComsumeHis);
                        //消费项目参与数+1
                        consumeItem.ParticipationNum = consumeItem.ParticipationNum + 1;
                        //记录红钻变动历史
                        RedRecordDetail recordDetail = new RedRecordDetail() {
                            RedRecordId = redRecord.Id,
                            MerchantId = userId,
                            RedDrill = consume_red,
                            Type = 1,
                            IsReceive = true,
                            CreateTime = DateTime.Now.ToUnix(),
                            RedProductionTime = 0
                        };
                        context.RedRecordDetail.Add(recordDetail);

                        //扣除商品剩余可兑换数量
                        if (consumeProduct.ProductNumLimit != null) {
                            consumeProduct.ProductNumLimit = consumeProduct.ProductNumLimit - 1;
                            //if (consumeProduct.ProductNumLimit == 0)//已无剩余可兑换数量，商品下架
                            //    consumeProduct.Status = EConsumeProductStatus.SoldOut;
                        }


                        _iUnitOfWork.Commit("RedRecord" + userId, "ConsumeItem", "ConsumeProduct");
                        userComsumeHis.RedRecordDetailId = recordDetail.Id;
                        var result = _iUnitOfWork.Commit();
                        if (result > 0) {
                            trans.Commit();
                            return true;
                        } else {
                            trans.Rollback();
                            return false;
                        }
                    } catch (Exception ex) {
                        trans.Rollback();
                        throw ex;
                    }
                }
            }
        }

        /// <summary>
        /// App获得用户兑换列表
        /// </summary>
        /// <param name="query"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        public PagedResult<user_exchange_product_his_dto> AppGetUserExchangeProductHis(PageQuery query, long userId) {
            var q = from h in context.UserComsumeHis.Where(o => o.UserId == userId && o.ConsumeType == EConsumeItemType.ExchangeProduct)
                    join p in context.ConsumeProduct on h.ProductId equals p.Id into t1
                    from tp in t1.DefaultIfEmpty()
                    select new user_exchange_product_his_dto() {
                        product_id = tp.Id,
                        product_title = h.Info,
                        product_img_url = tp.ImgUrl,
                        consume_red_drill = h.ConsumeRedDrill,
                        status = (int)h.Status,
                        create_time = h.CreateTime,
                        is_allow_exchange_again = (h.Status == EUserComsumeHisStatus.Failure && tp.Status == EConsumeProductStatus.Putaway) ? true : false

                    };
            var rows = q.OrderByDescending(c => c.create_time).Skip((query.page - 1) * query.size).Take(query.size).ToList();
            var result = new PagedResult<user_exchange_product_his_dto>(rows, q.Count(), query.page, query.size);
            return result;
        }
        #endregion
    }
}
